
#include "codec/ulaw_codec.h"
#include "logger.h"

unsigned char CUlawCodec::mExponentTable[256] = {
	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};

CUlawCodec::CUlawCodec()
{
}

CUlawCodec::~CUlawCodec()
{
}

NAudioFormats::ECodec CUlawCodec::getCodecType()
{
	return NAudioFormats::ULAW;
}

double CUlawCodec::convertFromS8ToDouble(int8_t pSample)
{
	return convertFromU8ToDouble(pSample);
}

int8_t CUlawCodec::convertFromDoubleToS8(double pSample)
{
	return convertFromDoubleToU8(pSample);
}

double CUlawCodec::convertFromU8ToDouble(uint8_t pSample)
{
	pSample = ~pSample;
	bool lNegative(false);
	// check if negative
	if(pSample & 0x80) {
		lNegative = true;
		pSample &= 0x7F; // reset MSB (bit 8)
	}
	unsigned int lExponent = pSample >> 4;

	// reset bit 7 and 6, and set bit 5 (bit 1 is the LSB)
	pSample &= 0x0F;
	pSample |= 0x10;

	unsigned int lUncompressed(pSample << 1);
	lUncompressed |= 0x01; // set LSB to 1
	lUncompressed <<= lExponent;

	// lowest: 100001b = 0x21 = 33;
	// highest: 1111110000000 = 0x1F80 = 8064
	if(lUncompressed < 33) {
		printl(LL_WARN, __FILE__, "Ulaw: Too low value. (%u)\n", lUncompressed);
	}
	if(lUncompressed > 8064) {
		printl(LL_WARN, __FILE__, "Ulaw: Too high value. (%u)\n", lUncompressed);
	}
	lUncompressed -= 32; // because ulaw add 32 before encoding -> only 8159 instead of 8191
	double lValue = static_cast<double>(lUncompressed) / 8159.0;
	if(lNegative) {
		lValue *= -1.0;
	}
	return lValue;
}

uint8_t CUlawCodec::convertFromDoubleToU8(double pSample)
{
	if(pSample > 1.0) {
		printl(LL_WARN, __FILE__, "Sample > 1.0 (%lf)", pSample);
		pSample = 1.0;
	}
	if(pSample < -1.0) {
		printl(LL_WARN, __FILE__, "Sample < -1.0 (%lf)", pSample);
		pSample = -1.0;
	}

	bool lNegative(false);
	if(pSample < 0.0) {
		lNegative = true;
		pSample *= -1.0;
	}
	unsigned int lUncompressed(static_cast<unsigned int>(pSample * 8159.0 + 0.5));
	if(lUncompressed > 8159) {
		printl(LL_WARN, __FILE__, "%u > 8159 (sample: %lf)\n",
				lUncompressed,
				pSample);
		lUncompressed = 8159;
	}
	// add 32 for compression which is required by ulaw
	lUncompressed += 32;
	// now lUncompressed can have a maximum of 8191 (= 13 bits which are set)

	// take the highest 8 bits from the first 13 bits of lUncompressed as
	// index for the exponent table.
	unsigned int lExponent = mExponentTable[lUncompressed >> 5];

	// store mantissa to lUncompressed (overwrite lUncompressed)
	lUncompressed >>= (lExponent + 1);
	lUncompressed &= 0x0F; // reset the fifth bit which is set

	uint8_t lCompressed((lExponent << 4) + lUncompressed);
	if(lNegative) {
		lCompressed |= 0x80;
	}
	return ~lCompressed;
}

double CUlawCodec::convertFromS16ToDouble(int16_t pSample)
{
	printl(LL_ERR, __FILE__, "Ulaw doesn't support 16bit signed samples.\n");
	return 0.0;
}

int16_t CUlawCodec::convertFromDoubleToS16(double pSample)
{
	printl(LL_ERR, __FILE__, "Ulaw can't create 16bit signed samples.\n");
	return 0;
}

double CUlawCodec::convertFromU16ToDouble(uint16_t pSample)
{
	printl(LL_ERR, __FILE__, "Ulaw doesn't support 16bit unsigned samples.\n");
	return 0.0;
}

uint16_t CUlawCodec::convertFromDoubleToU16(double pSample)
{
	printl(LL_ERR, __FILE__, "Ulaw can't create 16bit unsigned samples.\n");
	return 0;
}
